import socketserver
import struct
import time
import datetime
import threading
import os
import json
import re


server_port = 40010

timer_resend_firmware_handle = 0
timer_resend_firmware_data = 0
tcp_handle = 0
timer_resend_firmware_data_times = 0

protocol_head = 0x55aa55aa
protocol_min_len = 14
protocol_head_len = 12

protocol_timer_sysstatus_len = 21
protocol_timer_sensor_data_len = 32
protocol_ap_param_len = 48
protocol_sensor_cfg_len = 13

class MyTcpHandle(socketserver.StreamRequestHandler):
    crc16_table = [
	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
    ]
    n1_id = {}
    print_enable = 1

    
    def __init__(self,request,client_address,server):
        self.data = bytes()
        self.apid = 0
        self.save_file = 0
        super(MyTcpHandle, self).__init__(request,client_address,server)

        
    @staticmethod                                
    def crc(data):
        crc_value = 0
        for i in range(len(data)):
            crc_value = ((crc_value&0xffff)>>8)^MyTcpHandle.crc16_table[(crc_value^data[i])&0xff]
        return crc_value
    
    def handle(self):
        global timer_resend_firmware_handle
        global timer_resend_firmware_data
        global timer_resend_firmware_data_times
        global tcp_handle
        get_cmd_head_time = 0

        while True:
            try:
                data0 = self.request.recv(4096)
            except Exception as ext:
                try:
                    MyTcpHandle.n1_id[str_n1id]['link'] = 0
                    print(time.ctime(),'%08X 已经下线' % self.apid, ext)
                    self.request.close()
                    #del MyTcpHandle.client_dict['%08X' % self.apid]
                except:
                    pass
                break
            else:
                if not data0:
                    try:
                        MyTcpHandle.n1_id[str_n1id]['link'] = 0
                        print(time.ctime(),'%08X 已经下线' % self.apid)
                        self.request.close()
                        #del MyTcpHandle.client_dict['%08X' % self.apid]
                    except Exception as ext:
                        pass
                    break
                self.data += data0
                # self.save_file = open("data.txt",'wb')
                # self.save_file.write(data0)
                # self.save_file.close()
                # print('rev:',len(data0))
                # continue

                while len(self.data) >= protocol_min_len:
                    cmd_head, n1id, data_len, cmd1, cmd2 = struct.unpack('<IIHBB', self.data[0:12])
                    
                    if cmd_head != protocol_head:     #找协议头 没找到递减第一个字节 继续找  直到长度不符合要求 退出循环
                        self.data = self.data[1:]
                        continue
                    
                    if get_cmd_head_time == 0:        #记录找到协议头的时间 如果找到协议头超过一分钟还没有找到完整的包  重新开始找协议头
                        get_cmd_head_time = time.time()                   
                    elif time.time() > get_cmd_head_time + 60:
                        self.data = self.data[1:]
                        continue                       
                    
                    
                    if len(self.data) >= data_len + protocol_min_len:   #长度符合协议 进行crc计算
                        crc_value = MyTcpHandle.crc(self.data[:data_len + protocol_head_len])
                        if crc_value != (self.data[data_len + protocol_head_len] + (self.data[data_len + protocol_head_len+1]<<8)):
                            print('crc error')
                            self.data = self.data[1:]
                            continue  
                    else:       #退出继续等待新数据
                        break

                    get_cmd_head_time = 0
                    #数据通过crc校验
                    nb_list = bytes()
                    
                    file_name = time.strftime('%Y-%m-%d-%H.txt',time.localtime(time.time()))
                    timer_file_name = time.strftime('%Y-%m-%d.txt',time.localtime(time.time()))
                    str_n1id = '%04X' % n1id
                    self.apid = n1id
                    dir_name = "SDATA/%s/%s/" % (str_n1id,time.strftime('%Y-%m-%d',time.localtime(time.time())))
                    if os.path.isdir(dir_name) is False:
                        os.makedirs(dir_name)
                    if str_n1id in MyTcpHandle.n1_id:  #存在列表中 更新链接
                        MyTcpHandle.n1_id[str_n1id]['link'] = self.request
                    else:
                        MyTcpHandle.n1_id[str_n1id] = {}
                        MyTcpHandle.n1_id[str_n1id]['link'] = self.request
                        MyTcpHandle.n1_id[str_n1id]['real_file'] = open(dir_name+str_n1id + '-' + file_name,'a+')
                        MyTcpHandle.n1_id[str_n1id]['timer_file'] = open(dir_name+str_n1id + '-' + timer_file_name,'a+')
                        MyTcpHandle.n1_id[str_n1id]['down_firm'] = [bytes(),'',0,0]
                        MyTcpHandle.n1_id[str_n1id]['sensor'] = [0,0,0,0,0,0,0]
                        MyTcpHandle.n1_id[str_n1id]['cfg'] = dir_name+str_n1id + 'cfg.json'

                    if dir_name+str_n1id + '-' + file_name != MyTcpHandle.n1_id[str_n1id]['real_file'].name:
                        MyTcpHandle.n1_id[str_n1id]['real_file'] = open(dir_name+str_n1id + '-' + file_name,'a+')

                    if dir_name+str_n1id + '-' + timer_file_name != MyTcpHandle.n1_id[str_n1id]['timer_file'].name:
                        MyTcpHandle.n1_id[str_n1id]['timer_file'] = open(dir_name+str_n1id + '-' + timer_file_name,'a+')                            

                    MyTcpHandle.n1_id[str_n1id]['cfg'] = dir_name+str_n1id + 'cfg.json'  

                    self.data = self.data[protocol_head_len:]

                    if cmd1 ==  0xc0:          #AP上传的定时数据
                        if cmd2 == 0x01:
                            number, sys_time, data_time, gps_n_e_0, gps_n_e_1, sensor_num = struct.unpack('<IIIffB', self.data[0:protocol_timer_sysstatus_len])

                            write_data = '%d->[%f-%f]%s->%s: ' % (number,gps_n_e_0,gps_n_e_1,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())),time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(data_time)))
                            MyTcpHandle.n1_id[str_n1id]['timer_file'].write(write_data)    

                            timer_data = self.data[protocol_timer_sysstatus_len:]
                            sensor_id= rssi= s_v= rev_rssi= vol= mode= p_count= lost_c= resend_c= net_out_times= net_out_time= car_count= car0_count=car1_count= car2_count= car3_count= car4_count= ontime= car_head_time= car_to_car_dis = 0                            
                            for index in range(sensor_num):
                                sensor_id, rssi, s_v, rev_rssi, vol, mode, p_count, lost_c, resend_c, net_out_times, net_out_time, car_count, car0_count,car1_count, car2_count, car3_count, car4_count, ontime, car_head_time, car_to_car_dis = struct.unpack('<HbHbBBHHHBHHHHHHHBBB',timer_data[index*protocol_timer_sensor_data_len:(index+1)*protocol_timer_sensor_data_len])

                                str_data = '%04X %04X %d [%03d %03d] %04d [%04d %04d %04d] [%03d %03d] %03d [%03d %03d  %03d  %03d  %03d] [%04d %04d %04d]----' % (sensor_id, s_v, mode, rssi, rev_rssi, vol*20, p_count, lost_c, resend_c, net_out_times, net_out_time, car_count, car0_count,
                                    car1_count, car2_count, car3_count, car4_count, ontime, car_head_time, car_to_car_dis)
                                MyTcpHandle.n1_id[str_n1id]['timer_file'].write(str_data)
                                write_data += str_data
                            MyTcpHandle.n1_id[str_n1id]['timer_file'].write('\n')
                            MyTcpHandle.n1_id[str_n1id]['timer_file'].flush()
                            if MyTcpHandle.print_enable:
                                print('%s %s' % (str_n1id, write_data))

                            data2 = struct.pack('<IIHBBI',protocol_head,0,4,0xc0,0x02,number)
                            crc_value = MyTcpHandle.crc(data2)
                            data2 += bytes([crc_value & 0xff,((crc_value>>8) & 0xff)])
                            self.request.sendall(data2)

                    elif cmd1 ==  0xc1:          #AP上传的系统参数
                        if cmd2 == 0x01:
                            crc, code, ap_id, s_v, io_v, ap_v, on_delay, off_to_on_min_time, ip0, port0, switch0, timer_data_time_sec0, ip1, port1, switch1, timer_data_time_sec1,ip2, port2, switch2, timer_data_time_sec2, sensor_count = struct.unpack('<HIIHHHHHIHBHIHBHIHBHB', self.data[0:protocol_ap_param_len])
                            cfg_dict = [{}]
                            cfg_dict[0]['crc'] = crc
                            cfg_dict[0]['code'] = code
                            cfg_dict[0]['ap_id'] = hex(ap_id) 
                            cfg_dict[0]['s_v'] = hex(s_v) 
                            cfg_dict[0]['io_v'] = hex(io_v) 
                            cfg_dict[0]['ap_v'] = hex(ap_v)                                                            
                            cfg_dict[0]['on_delay'] = on_delay
                            cfg_dict[0]['off_to_on_min_time'] = off_to_on_min_time
                            cfg_dict[0]['ip0'] = '%d.%d.%d.%d' % ((ip0>>24)&0xff, (ip0>>16)&0xff, (ip0>>8)&0xff, (ip0)&0xff)
                            cfg_dict[0]['port0'] = port0
                            cfg_dict[0]['switch0'] = hex(switch0)
                            cfg_dict[0]['timer_data_time_sec0'] = timer_data_time_sec0  
                            cfg_dict[0]['ip1'] = '%d.%d.%d.%d' % ((ip1>24)&0xff, (ip1>>16)&0xff, (ip1>>8)&0xff, (ip1)&0xff)   
                            cfg_dict[0]['port1'] = port1
                            cfg_dict[0]['switch1'] = hex(switch1)
                            cfg_dict[0]['timer_data_time_sec1'] = timer_data_time_sec1                             
                            cfg_dict[0]['ip2'] = '%d.%d.%d.%d' % ((ip2>>24)&0xff, (ip2>>16)&0xff, (ip2>>8)&0xff, (ip2)&0xff)   
                            cfg_dict[0]['port2'] = port2
                            cfg_dict[0]['switch2'] = hex(switch2)       
                            cfg_dict[0]['timer_data_time_sec2'] = timer_data_time_sec2                                                 
                            cfg_dict[0]['sensor_count'] = sensor_count   

                            data = self.data[protocol_ap_param_len:]
                            for i in range(sensor_count):
                                cfg_dict.append({})
                                sesnor_id, mode, on_delay_s, off_to_on_min_time_s, lane, lane_index, distance, direction, lane_direction = struct.unpack('<HBHHBBHBB', data[i*protocol_sensor_cfg_len:(i+1)*protocol_sensor_cfg_len])
                                cfg_dict[i+1]['sensor_id'] = hex(sesnor_id)
                                cfg_dict[i+1]['mode'] = hex(mode)
                                cfg_dict[i+1]['on_delay_s'] = on_delay_s
                                cfg_dict[i+1]['off_to_on_min_time_s'] = off_to_on_min_time_s
                                cfg_dict[i+1]['lane'] = lane
                                cfg_dict[i+1]['lane_index'] = lane_index
                                cfg_dict[i+1]['distance'] = distance
                                cfg_dict[i+1]['direction'] = direction                                
                                cfg_dict[i+1]['lane_direction'] = lane_direction

                            if MyTcpHandle.print_enable:
                                print(str_n1id,json.dumps(cfg_dict,indent=4,ensure_ascii=False))                            

                            write_json = open(MyTcpHandle.n1_id[str_n1id]['cfg'],'w')
                            json.dump(cfg_dict,write_json,indent=4,ensure_ascii=False)
                            write_json.close()

                            data2 = struct.pack('<IIHBBH',protocol_head,0,2,0xc1,0x02,crc)
                            crc_value = MyTcpHandle.crc(data2)
                            data2 += bytes([crc_value & 0xff,((crc_value>>8) & 0xff)])
                            self.request.sendall(data2)
                        elif cmd2 == 0x04:
                            print(str_n1id,'写入参数成功')
                            
                    elif cmd1 == 0xc2:
                        if cmd2 == 0x02:
                            packet_seq, = struct.unpack('<H', self.data[0:2])
                            #file_name = self.data[4:-2]
                            if packet_seq > MyTcpHandle.n1_id[str_n1id]['down_firm'][2]:
                                if timer_resend_firmware_handle != 0:
                                    timer_resend_firmware_handle.cancel()    
                                print(str_n1id, '下载成功')                            
                                break
                            MyTcpHandle.n1_id[str_n1id]['down_firm'][3] = packet_seq
                            if len(MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:])>=1024:
                                data = MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:packet_seq*1024]
                            else:
                                data = MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:]
                                
                            data2 = struct.pack('<IIHBBHH',protocol_head,0,len(data)+4,0xC2,1,MyTcpHandle.n1_id[str_n1id]['down_firm'][2],MyTcpHandle.n1_id[str_n1id]['down_firm'][3])
                            
                            data2 = data2 + data
                            crc_value = MyTcpHandle.crc(data2)
                            data2 += bytes([(crc_value) & 0xff,(crc_value>>8) & 0xff])
                            if timer_resend_firmware_handle != 0:
                                timer_resend_firmware_handle.cancel()
                            self.request.sendall(data2)
                            timer_resend_firmware_handle = threading.Timer(3, timer_resend_firmware_data_func)
                            timer_resend_firmware_handle.start()
                            timer_resend_firmware_data = data2
                            timer_resend_firmware_data_times = 0
                            tcp_handle = self.request
                            if MyTcpHandle.print_enable:
                                print(str_n1id,'下载固件 总包数%d 当前包数%d'%(MyTcpHandle.n1_id[str_n1id]['down_firm'][2],MyTcpHandle.n1_id[str_n1id]['down_firm'][3]))
                    
                    elif cmd1 == 0xc3:
                        if cmd2 == 0x02: # 下发升级命令 ack
                            print(str_n1id,'收到升级指令')
                        elif cmd2 == 0xf2: # 下发升级命令 ack
                            print(str_n1id,'设备没有正确的sensor固件')                           
                        elif cmd2 == 0x04: # 升级状态包
                            sensor_count = struct.unpack('<B', self.data[0:1])
                            sensor_id = v = packet_count = packet_seq = 0
                            print(str_n1id,'sensor_count=%d 升级进度：' % sensor_count)
                            for i in range(sensor_count):
                                sensor_id, v, packet_count,packet_seq = struct.unpack('<HHHH', self.data[1+i*8:1+(i+1)*8])
                                print(' sid=%04X V:%04X [%d/%d]' % (sensor_id, v, packet_count,packet_seq))
                                



                    self.data = self.data[data_len+2:]
                    break








                    #if MyTcpHandle.print_enable:
                        #   print('head:',n1id,cmd_lengh)
                    if cmd1 == 0xfe:
                        cmd1,cmd2,N1ID = struct.unpack('<BBI', self.data[0:6])
                        MyTcpHandle.n1_id[str_n1id]['sensor'][0] = '%04X'%N1ID
                        print('beefbeef 连接')
                    if cmd1 == 0x87:
                        cmd1,cmd2,timer_data_count = struct.unpack('BBB', self.data[0:3])
                        if MyTcpHandle.print_enable:
                            print('定时流量=%d' % timer_data_count)
                        timer_data = []
                        for i in range(timer_data_count):
                            timer_data.append(self.data[3+i*198:3+(i+1)*198])
                            
                            number,systime,datatime,gpsn,gpse = struct.unpack('<IIIff', timer_data[i][0:20])
                            write_data = '[%f-%f]%s->%s:' % (gpsn,gpse,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())),time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(datatime)))
                            MyTcpHandle.n1_id[str_n1id]['timer_file'].write(write_data)
                            for j in range(7):
                                sid,sv,rssi,all_p,lost_p,resend_p,car,on_rate,volgate,sensor_rev_rssi,n1,n2,n3 = struct.unpack('<HHbHHHHBBbBBI', timer_data[i][44+j*22:44+(j+1)*22])
                                str_data = '%04X %d %03d %03d:%03d %03d %03d %03d %03d %03d    ' % ( sid,sv,volgate*2,rssi,sensor_rev_rssi,all_p,lost_p,resend_p,car,on_rate)
                                MyTcpHandle.n1_id[str_n1id]['timer_file'].write(str_data)

                            MyTcpHandle.n1_id[str_n1id]['timer_file'].write('\n')
                            MyTcpHandle.n1_id[str_n1id]['timer_file'].flush()
                            nb_list += timer_data[i][0:4]
                            if MyTcpHandle.print_enable:
                                print('定时流量%d:->%d' % (i,number))
                        data2 = struct.pack('<IIIHBBB',protocol_head,0,0,2+timer_data_count*4,0,0x87,1)
                        data2 = data2 + nb_list
                        crc_value = MyTcpHandle.crc(data2[4:])
                        data2 += bytes([(crc_value>>8) & 0xff,crc_value & 0xff])
                        self.request.sendall(data2)
                        self.data = self.data[cmd_lengh+2:]

                        
                    elif cmd1 == 0x88:
                        cmd1,cmd2,realtime_data_count = struct.unpack('BBB', self.data[0:3])
                        if MyTcpHandle.print_enable:
                            print('实时流量=%d' % realtime_data_count)
                        realtime_data = []
                        str_d = ''
                        for i in range(realtime_data_count):
                            realtime_data.append(self.data[3+i*19:3+(i+1)*19])
                            try:
                                sid,number,sys_time,data_time,postion,ontime = struct.unpack('<HIIIBI', realtime_data[i][0:19])
                            except Exception as ext:
                                if MyTcpHandle.print_enable:
                                    print('error:',i,)
                                continue
                            MyTcpHandle.n1_id[str_n1id]['sensor'][postion&0x0f] = '%04X'%sid
                            nb_list += realtime_data[i][2:6]
                            if 'BEEFBEEF' in MyTcpHandle.n1_id.keys():
                                if MyTcpHandle.n1_id['BEEFBEEF']['sensor'][0] == str_n1id and MyTcpHandle.n1_id['BEEFBEEF']['link']!=0:
                                    try:
                                        MyTcpHandle.n1_id['BEEFBEEF']['link'].sendall(struct.pack('<I',0xbeefbeef) + realtime_data[i][0:19])
                                    except Exception as ext:
                                        print('error:',i,)
                                    print('beefbeef 发送数据','%04X'%sid)
                                    
                            if postion & 0xf0 == 0:
                                str_d += '实时流量%d:%04X->%d    ' % (i,sid,number)
                                write_data = '[off]SID=%04X_%d NO.=%d sys_time=%s car_time=%s ON_time=%d秒:%d毫秒\n' % (sid,postion&0x0f,number,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sys_time)),
                                                                time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(data_time)),int(ontime/1000),ontime%1000)
                                
                            else:
                                try:
                                    sid,number,sys_time,data_time,postion,s_seq,resend_times,event = struct.unpack('<HIIIBBBH', realtime_data[i][0:19])
                                except Exception as ext:
                                    if MyTcpHandle.print_enable:
                                        print('error:',i,)
                                    continue
                                write_data = '[on]SID=%04X_%d NO.=%d sys_time=%s car_time=%s ON_event=%d秒:%d毫秒 seq=%d resend_times=%d\n' % (sid,postion&0x0f,number,time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sys_time)),
                                                                time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(data_time)),(event>>10)&0x1f,event&0x3ff,s_seq,resend_times)

                                
                            MyTcpHandle.n1_id[str_n1id]['real_file'].write(write_data)
                            
                        if MyTcpHandle.print_enable:
                            print(str_d)
                        MyTcpHandle.n1_id[str_n1id]['real_file'].flush()
                        
                        data2 = struct.pack('<IIIHBBB',protocol_head,0,0,2+realtime_data_count*4,0,0x88,1)
                        data2 = data2 + nb_list
                        crc_value = MyTcpHandle.crc(data2[4:])
                        data2 += bytes([(crc_value>>8) & 0xff,crc_value & 0xff])                            
                        self.request.sendall(data2)

                        self.data = self.data[cmd_lengh+2:]
        
                    elif cmd1 == 0x84:
                        cmd1,cmd2,cmd3,packet_num,packet_seq = struct.unpack('<BBBHH', self.data[0:7])
                        file_name = self.data[7:-2]
                        if packet_seq > MyTcpHandle.n1_id[str_n1id]['down_firm'][2]:
                            break
                        MyTcpHandle.n1_id[str_n1id]['down_firm'][3] = packet_seq
                        if len(MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:])>=1024:
                            data = MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:packet_seq*1024]
                        else:
                            data = MyTcpHandle.n1_id[str_n1id]['down_firm'][0][(packet_seq-1)*1024:]
                            
                        data2 = struct.pack('<IIIHBBBBHH',protocol_head,0,0,len(data)+7,0,0x84,1,0XA0,MyTcpHandle.n1_id[str_n1id]['down_firm'][2],MyTcpHandle.n1_id[str_n1id]['down_firm'][3])
                        
                        data2 = data2 + data
                        crc_value = MyTcpHandle.crc(data2[4:])
                        data2 += bytes([(crc_value>>8) & 0xff,crc_value & 0xff])
                        if timer_resend_firmware_handle != 0:
                            timer_resend_firmware_handle.cancel()
                        self.request.sendall(data2)
                        self.data = self.data[cmd_lengh+2:]
                        timer_resend_firmware_handle = threading.Timer(3, timer_resend_firmware_data_func)
                        timer_resend_firmware_handle.start()
                        timer_resend_firmware_data = data2
                        timer_resend_firmware_data_times = 0
                        tcp_handle = self.request
                        if MyTcpHandle.print_enable:
                            print('下载固件 总包数%d 当前包数%d'%(MyTcpHandle.n1_id[str_n1id]['down_firm'][2],MyTcpHandle.n1_id[str_n1id]['down_firm'][3]))



                    elif cmd1 == 0x86:
                        cmd1,cmd2,sys_time,id1,p1,id2,p2,id3,p3,id4,p4,id5,p5,id6,p6,id7,p7, = struct.unpack('<BBIHBHBHBHBHBHBHB', self.data[0:27])
                        if MyTcpHandle.print_enable:                            
                            if id1:
                                print('S_[%04X] 升级进度%d' % (id1,p1))
                            if id2:
                                print('S_[%04X] 升级进度%d' % (id2,p2))
                            if id3:
                                print('S_[%04X] 升级进度%d' % (id3,p3))                                
                            if id4:
                                print('S_[%04X] 升级进度%d' % (id4,p4))
                            if id5:
                                print('S_[%04X] 升级进度%d' % (id5,p5))
                            if id6:
                                print('S_[%04X] 升级进度%d' % (id6,p6))
                            if id7:
                                print('S_[%04X] 升级进度%d' % (id7,p7))                                

                        self.data = self.data[cmd_lengh+2:]

                    elif cmd1 == 0x83:
                        cmd1,cmd2 =  struct.unpack('BB',self.data[0:2])
                        if cmd2 == 0x01:
                            MyTcpHandle.n1_id[str_n1id]['cfg'] = self.data[0:cmd_lengh]
                            cmd1,cmd2,crc,sys_time,n1_v,sensor_v,sensor_num,ip1_0,ip1_1,ip1_2,ip1_3,ip2_0,ip2_1,ip2_2,ip2_3,port1,port2,data_save_time,real_switch= struct.unpack('<BBHIBHBBBBBBBBBHHHB', self.data[0:27])
                            
                            print('N1_%s V=%d S_V=%d ip1[%d.%d.%d.%d port:%d] ip2[%d.%d.%d.%d port:%d] data_save_time=%d real_on_sw:%d real_off_sw:%d' % (str_n1id,n1_v,sensor_v,
                                                                            ip1_0,ip1_1,ip1_2,ip1_3,port1,ip2_0,ip2_1,ip2_2,ip2_3,port2,data_save_time,(real_switch>>4),(real_switch&0x0f)))

                            for i in range(7):
                                s_id,off_to_on_min_t_ms,d1,d2 = struct.unpack('<HHIH', self.data[100+27+i*10:100+27+(i+1)*10])
                                print('%04X:%dms' % (s_id,off_to_on_min_t_ms))
                        elif cmd2 == 0x02:
                            cmd11,cmd22,crc1 = struct.unpack('<BBH',MyTcpHandle.n1_id[str_n1id]['cfg'][0:4])
                            cmd1,cmd2,crc =  struct.unpack('<BBH',self.data[0:4])
                            print('N1_%s 写参数返回crc=%d:%d' % (str_n1id,crc1,crc))
                        self.data = self.data[cmd_lengh+2:]

                    elif cmd1 == 0xa1:
                        cmd1,cmd2,data_count,number= struct.unpack('<BBBI', self.data[0:7])
                        str_d = "IO_data-%d-%d:" % (number,data_count)
                        status = ['off','on']
                        for i in range(data_count):
                            io,sys_time,second,ms = struct.unpack('<BIIH', self.data[7+i*11:7+(i+1)*11])
                            str_d += '[%s: io=%d:%d:%d %s ]    ' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sys_time)),io,second,(ms&0x7FFF),status[((ms&0x8000)>>15)])
                                
                        str_d + '\n'
                        MyTcpHandle.n1_id[str_n1id]['real_file'].write(str_d)
                            
                        if MyTcpHandle.print_enable:
                            print(str_d)
                        MyTcpHandle.n1_id[str_n1id]['real_file'].flush()
                        
                        data2 = struct.pack('<IIIHBBBIB',protocol_head,0,0,2+5,0,0xa1,1,number,data_count)
                        crc_value = MyTcpHandle.crc(data2[4:])
                        data2 += bytes([(crc_value>>8) & 0xff,crc_value & 0xff])                            
                        self.request.sendall(data2)

                        self.data = self.data[cmd_lengh+2:]  
                                
def start_down_firm(str_n1id,file_name):

    MyTcpHandle.n1_id[str_n1id]['down_firm'][0] = open(file_name,'rb').read()
    MyTcpHandle.n1_id[str_n1id]['down_firm'][1] = file_name 
    str_len = len(file_name)
    MyTcpHandle.n1_id[str_n1id]['down_firm'][2] = int(len(MyTcpHandle.n1_id[str_n1id]['down_firm'][0])/1024)
    if len(MyTcpHandle.n1_id[str_n1id]['down_firm'][0])%1024 > 0:
        MyTcpHandle.n1_id[str_n1id]['down_firm'][2] += 1
    MyTcpHandle.n1_id[str_n1id]['down_firm'][3] = 0    
    data2 = struct.pack('<IIHBBHH',protocol_head,0,str_len+4+2,0xc2,1,MyTcpHandle.n1_id[str_n1id]['down_firm'][2],MyTcpHandle.n1_id[str_n1id]['down_firm'][3])

    crc_value = MyTcpHandle.crc(MyTcpHandle.n1_id[str_n1id]['down_firm'][0])
    data2 = data2 + bytes([(crc_value) & 0xff,(crc_value>>8) & 0xff])+file_name.encode()
    crc_value = MyTcpHandle.crc(data2)
    data2 += bytes([(crc_value) & 0xff,(crc_value>>8) & 0xff])
    try:
        MyTcpHandle.n1_id[str_n1id]['link'].sendall(data2)
        print('开始下载文件：',MyTcpHandle.n1_id[str_n1id]['down_firm'][1],'长度=%d'%MyTcpHandle.n1_id[str_n1id]['down_firm'][2])
    except Exception as ext:
        print(ext)
    MyTcpHandle.print_enable = 1


def start_updata_sensor(str_n1id,id_list):
    sensor_id_list = bytes()
    print(id_list)
    try:
        for s in id_list:
            sensor_id_list += struct.pack('<H',int(s,16))
            
        data2 = struct.pack('<IIHBBB',protocol_head,0,len(sensor_id_list)+1,0xc3,1,int(len(sensor_id_list)/2))
        data2 += sensor_id_list
        crc_value = MyTcpHandle.crc(data2)
        data2 += bytes([(crc_value) & 0xff,(crc_value>>8) & 0xff])
        MyTcpHandle.n1_id[str_n1id]['link'].sendall(data2)
        print('开始升级sensor：',id_list)
        MyTcpHandle.print_enable = 1
    except Exception as ext:
        print('升级指令错误',ext)
        
def start_adjust_sensor(str_n1id,id_list):
    sensor_id_list = bytes()
    print(id_list)
    try:
        for s in id_list:
            sensor_id_list += struct.pack('<H',int(s,16))
            
        data2 = struct.pack('<IIIHBBBB',protocol_head,0,0,len(sensor_id_list)+3,0,0xa0,1,int(len(sensor_id_list)/2))
        data2 += sensor_id_list
        crc_value = MyTcpHandle.crc(data2[4:])
        data2 += bytes([(crc_value>>8) & 0xff,crc_value & 0xff])
        MyTcpHandle.n1_id[str_n1id]['link'].sendall(data2)
        print('下发校准命令：',id_list)
        MyTcpHandle.print_enable = 1
    except Exception as ext:
        print('校准指令错误',ext)

def read_cfg(str_n1id):
    
    data2 = struct.pack('<IIHBB',protocol_head,0,0,0xc1,0x00)
    crc_value = MyTcpHandle.crc(data2)
    data2 += bytes([crc_value & 0xff,((crc_value>>8) & 0xff)])
    try:
        MyTcpHandle.n1_id[str_n1id]['link'].sendall(data2)
        print('读参数N1=：',str_n1id)
    except:
        print("读N1_%08X参数错误",str_n1id)


def timer_resend_firmware_data_func():
    global timer_resend_firmware_data
    global tcp_handle
    global timer_resend_firmware_data_times
    global timer_resend_firmware_handle

    if timer_resend_firmware_data_times < 5:
        timer_resend_firmware_data_times += 1
        timer_resend_firmware_handle = threading.Timer(3, timer_resend_firmware_data_func)
        timer_resend_firmware_handle.start()

    try:
        tcp_handle.sendall(timer_resend_firmware_data)
    except Exception as ext:
        print('重传固件error:',ext)
    print('重传固件第%d次:'%timer_resend_firmware_data_times)


str_help = '''********************************************************************************
    版本：0.1
    功能：ETC服务器
    操作指令：
    1.输入 ？ 返回帮助信息
    
    2.输入 ls 返回已经连接的N1ID
    
    3.输入 down n1id 选择下载固件

    4. 输入 updata n1id sensor_id1 ...  启动升级sensor 可以输入多个sensorid

    5.输入 readcfg n1id 读取N1参数 显示存储的固件版本号
    
    6.输入 openprint 会打印N1上传数据信息

    7.输入 closeprint 会关闭打印信息

    8.输入 setsf[n1id] [index] [delay ms]  设置输入索引位置的sensor的分车阈值

    9.输入 setid [n1id] [index] [sensorid]  设置输入索引位置的sensor id

********************************************************************************
'''


        
    
class CmdThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global str_help
        while True:
            str_cmd = input('>>')

            if str_cmd == '':

                continue
            
            str_cmd_list = str_cmd.split(' ')
            
            if str_cmd == 'ls':
                for key in MyTcpHandle.n1_id:
                    if MyTcpHandle.n1_id[key]['link'] != 0:
                        print('已经连接的N1:',key,MyTcpHandle.n1_id[key]['sensor'])             
            if str_cmd == '?':
                print(str_help)
            if str_cmd == 'openprint':
                MyTcpHandle.print_enable = 1
                print('打开打印信息')
            if str_cmd == 'closeprint':
                MyTcpHandle.print_enable = 0                
                print('关闭打印信息')
            if str_cmd_list[0] == 'down':
                if len(str_cmd_list) < 2:
                    print('输入N1ID')
                    continue
                list_name = []
                index = 0
                for file in os.listdir(os.getcwd()):   
                    if os.path.splitext(file)[1]=='.bin':  
                        list_name.append(file)
                        print('[%d]->%s'%(index,file))
                        index += 1
                    
                choose = int(input('>>'))
                if choose < len(list_name) and str_cmd_list[1].upper() in MyTcpHandle.n1_id:
                    start_down_firm(str_cmd_list[1].upper(),list_name[choose])
                else:
                    print('选择错误 没有这个N1 或者文件索引错误')
            if str_cmd_list[0] == 'updata':
                if len(str_cmd_list) < 3:
                    print('输入N1ID')
                    continue                
                start_updata_sensor(str_cmd_list[1].upper(),str_cmd_list[2:])
            if str_cmd_list[0] == 'adjust':
                if len(str_cmd_list) < 3:
                    print('输入N1ID')
                    continue                
                start_adjust_sensor(str_cmd_list[1].upper(),str_cmd_list[2:])                
            if str_cmd_list[0] == 'readcfg':
                if len(str_cmd_list) < 2:
                    print('输入N1ID')
                    continue
                if str_cmd_list[1].upper() in MyTcpHandle.n1_id:
                    read_cfg(str_cmd_list[1].upper())
                else:
                    print('选择错误 没有这个N1 或者文件索引错误')
            if str_cmd_list[0] == 'setsf':
                try:
                    if 'cfg'  not in MyTcpHandle.n1_id[str_cmd_list[1].upper()] or len(MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg']) < 175:
                        print('先读一下参数 才能设置')
                        continue
                except Exception as ext:
                    print(ext)
                try:
                    index = int(str_cmd_list[2])
                    if index > 6:
                        print('索引超出范围 0-6')
                        continue
                    f_ms = struct.pack('<H',int(str_cmd_list[3]))
                    
                    MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'] = MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][0:100+27+index*10+2] + f_ms + MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][100+27+index*10+4:]
                    
                    
                    cmd1,cmd2,crc,sys_time,n1_v,sensor_v,sensor_num,ip1_0,ip1_1,ip1_2,ip1_3,ip2_0,ip2_1,ip2_2,ip2_3,port1,port2,data_save_time,real_switch= struct.unpack('<BBHIBHBBBBBBBBBHHHB', MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][0:27])
                    print('参数变为：')        
                    print('N1_%s V=%d S_V=%d ip1[%d.%d.%d.%d port:%d] ip2[%d.%d.%d.%d port:%d] data_save_time=%d real_on_sw:%d real_off_sw:%d' % (str_cmd_list[1].upper(),n1_v,sensor_v,
                                                                            ip1_0,ip1_1,ip1_2,ip1_3,port1,ip2_0,ip2_1,ip2_2,ip2_3,port2,data_save_time,(real_switch>>4),(real_switch&0x0f)))

                    for i in range(7):
                        s_id,off_to_on_min_t_ms,d1,d2 = struct.unpack('<HHIH', MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][100+27+i*10:100+27+(i+1)*10])
                        print('%04X:%dms' % (s_id,off_to_on_min_t_ms))
                    print('******************************************')
                except Exception as ext:
                    print('setsf',ext)
            if str_cmd_list[0] == 'setid':
                try:
                    if 'cfg'  not in MyTcpHandle.n1_id[str_cmd_list[1].upper()] or len(MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg']) < 175:
                        print('先读一下参数 才能设置')
                        continue
                except Exception as ext:
                    print(ext)
                try:
                    index = int(str_cmd_list[2])
                    if index > 6:
                        print('索引超出范围 0-6')
                        continue
                    sid = struct.pack('<H',int(str_cmd_list[3],16))
                    
                    MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'] = MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][0:100+27+index*10] + sid + MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][100+27+index*10+2:]
                    
                    
                    cmd1,cmd2,crc,sys_time,n1_v,sensor_v,sensor_num,ip1_0,ip1_1,ip1_2,ip1_3,ip2_0,ip2_1,ip2_2,ip2_3,port1,port2,data_save_time,real_switch= struct.unpack('<BBHIBHBBBBBBBBBHHHB', MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][0:27])
                    print('参数变为：')        
                    print('N1_%s V=%d S_V=%d ip1[%d.%d.%d.%d port:%d] ip2[%d.%d.%d.%d port:%d] data_save_time=%d real_on_sw:%d real_off_sw:%d' % (str_cmd_list[1].upper(),n1_v,sensor_v,
                                                                            ip1_0,ip1_1,ip1_2,ip1_3,port1,ip2_0,ip2_1,ip2_2,ip2_3,port2,data_save_time,(real_switch>>4),(real_switch&0x0f)))

                    for i in range(7):
                        s_id,off_to_on_min_t_ms,d1,d2 = struct.unpack('<HHIH', MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'][100+27+i*10:100+27+(i+1)*10])
                        print('%04X:%dms' % (s_id,off_to_on_min_t_ms))
                    print('******************************************')
                except Exception as ext:
                    print('setid',ext)
            if str_cmd_list[0] == 'downcfg':
                try:
                    f = open( MyTcpHandle.n1_id[str_cmd_list[1].upper()]['cfg'],'r')
                    cfg_dict = json.load(f)
                except Exception as ext:
                    print('down_cfg0',ext)
                    continue

                crc = cfg_dict[0]['crc']
                code = cfg_dict[0]['code']
                ap_id	=	int(cfg_dict[0]['ap_id'],16)
                s_v =       int(cfg_dict[0]['s_v'],16) 
                io_v =       int(cfg_dict[0]['io_v'],16)  
                ap_v  =      int(cfg_dict[0]['ap_v'] ,16)                
                on_delay	=	cfg_dict[0]['on_delay']
                off_to_on_min_time	=	cfg_dict[0]['off_to_on_min_time']
                v = cfg_dict[0]['ip0'].split('.')
                ip0	= (int(v[0])<<24) + (int(v[1])<<16) + (int(v[2])<<8) + int(v[3])	
                port0	=	cfg_dict[0]['port0']
                switch0	=	int(cfg_dict[0]['switch0'],16)
                timer_data_time_sec0 = cfg_dict[0]['timer_data_time_sec0']                
                v = cfg_dict[0]['ip1'].split('.')
                ip1	= (int(v[0])<<24) + (int(v[1])<<16) + (int(v[2])<<8) + int(v[3])	
                port1	=	cfg_dict[0]['port1']
                switch1	=	int(cfg_dict[0]['switch1'],16)
                timer_data_time_sec1 = cfg_dict[0]['timer_data_time_sec1']               
                v = cfg_dict[0]['ip2'].split('.')
                ip2	= (int(v[0])<<24) + (int(v[1])<<16) + (int(v[2])<<8) + int(v[3])	
                port2	=	cfg_dict[0]['port2']
                switch2	=	int(cfg_dict[0]['switch2'],16)
                timer_data_time_sec2 = cfg_dict[0]['timer_data_time_sec2']
                sensor_count	=	cfg_dict[0]['sensor_count']
                
                data = struct.pack('<IIHHHHHIHBHIHBHIHBHB', code, ap_id, s_v, io_v, ap_v, on_delay, off_to_on_min_time, ip0, port0, switch0, timer_data_time_sec0, ip1, port1, switch1, timer_data_time_sec1, ip2, port2, switch2, timer_data_time_sec2, sensor_count)            

                for i in range(sensor_count):
                    sesnor_id=	int(cfg_dict[i+1]['sensor_id'],16)
                    mode=	int(cfg_dict[i+1]['mode'],16)
                    on_delay_s=	cfg_dict[i+1]['on_delay_s']
                    off_to_on_min_time_s=	cfg_dict[i+1]['off_to_on_min_time_s']
                    lane=	cfg_dict[i+1]['lane']
                    lane_index = cfg_dict[i+1]['lane_index']                
                    distance=	cfg_dict[i+1]['distance']
                    direction = cfg_dict[i+1]['direction']
                    lane_direction=	cfg_dict[i+1]['lane_direction']
                    data1 = struct.pack('<HBHHBBHBB', sesnor_id, mode, on_delay_s, off_to_on_min_time_s, lane, lane_index, distance, direction,lane_direction)
                    data += data1

                crc_value = MyTcpHandle.crc(data)
                data = struct.pack('<IIHBBH',protocol_head,0,sensor_count*protocol_sensor_cfg_len+protocol_ap_param_len,0xc1,0x03,crc_value) + data
                crc_value = MyTcpHandle.crc(data)
                data += bytes([crc_value & 0xff,((crc_value>>8) & 0xff)])
                try:
                    MyTcpHandle.n1_id[str_cmd_list[1].upper()]['link'].sendall(data)
                    print('写参数N1=：',str_cmd_list[1].upper())
                except:
                    print("写N1_%08X参数错误",str_cmd_list[1].upper())
                    
                
def main():

    cmd_thread = CmdThread()
    cmd_thread.start()
    socketserver.socket.setdefaulttimeout(61*10)
    server = socketserver.ThreadingTCPServer(('0.0.0.0',server_port),MyTcpHandle)
    try:
        server.serve_forever()
    except Exception as ext:
        print('server_forever error %s' % ext)

        
if __name__ == '__main__':
    main()


